package indi.cloud.common.convert;

import indi.cloud.common.utils.CommonDataUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author yangyifan
 * @version 1.0
 * @date 2024/2/2 15:25
 * @Description
 */
public class UnitConvert<T> {
    private T data;
    private Map<String, UnitEnum> unit = new HashMap<>();

    public static <U> UnitConvert init(U data) {
        UnitConvert unitConvert = new UnitConvert();
        unitConvert.data = data;
        return unitConvert;
    }

    public Object convert() {
        if (data == null) {
            return null;
        }
        if (data instanceof JSONObject) {
            foreachUnitJSONObject(data);
        } else if (data instanceof JSONArray) {
            ((JSONArray) data).stream().forEach(x -> {
                foreachUnitJSONObject(x);
            });
        } else if (data instanceof List) {
            List tempData = (List) this.data;
            if (tempData.size() == 0) {
                return data;
            }
            Class<?> aClass = tempData.get(0).getClass();
            if (aClass == JSONObject.class) {
                tempData.stream().forEach(x -> {
                    foreachUnitJSONObject(x);
                });
            } else {
                tempData.stream().forEach(y -> {
                    try {
                        foreachUnitEntity(y);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }

        } else if (data instanceof Map) {
            Map tempMap = (Map) data;
            for (String key : unit.keySet()) {
                if (tempMap.containsKey(key)) {
                    Object o = tempMap.get(key);
                    tempMap.put(key, convertImpl(o, unit.get(key)));
                }
            }
            return tempMap;
        } else {
            try {
                JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(data));
                foreachUnitEntity(data);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return data;
    }

    private void foreachUnitEntity(Object object) throws IllegalAccessException {
        Class<?> aclass = object.getClass();
        Field[] fields = aclass.getDeclaredFields();
        for (String key : unit.keySet()) {
            for (Field field : fields) {
                String name = field.getName();
                if (StringUtils.equals(name, key)) {
                    field.setAccessible(true);
                    field.set(object, convertImpl(field.get(object), unit.get(key)));
                }
            }
        }

    }


    private void foreachUnitJSONObject(Object x) {
        for (String key : unit.keySet()) {
            if (((JSONObject) x).containsKey(key)) {
                Object o = ((JSONObject) x).get(key);
                ((JSONObject) x).put(key, convertImpl(o, unit.get(key)));
            }
        }
    }

    private Object convertImpl(Object value, UnitEnum unitEnum) {

        if (unitEnum.getReturnType() == BigDecimal.class) {
            return CommonDataUtils.strToDeci(value, unitEnum.numberSale);
        }
        if (unitEnum.getReturnType() == String.class) {
            String type = unitEnum.getTypeName();
            switch (type) {
                //千分位格式化
                case "THOUSANDTH":
                    return fmtMicrometer(CommonDataUtils.strToDeci(value, 4));
            }
        }
        return value;
    }

    /**
     * @param key 需要转换得key
     * @param
     * @return
     */
    public UnitConvert unit(String key, UnitEnum unitEnum) {
        unit.put(key, unitEnum);
        return this;
    }

    /**
     * @param money 金额
     * @return String 格式化后金额（格式：12,345.67）
     * @Description: 四舍五入格式化金额，千分位，并保留两位小数
     */
    public static String fmtMicrometer(BigDecimal money) {

        if (null == money) {
            return null;
        }
        try {
            DecimalFormat df = new DecimalFormat(",##0.00");
            return df.format(money);
        } catch (Exception e) {
            return null;
        }
    }
}
